package com.btpj.shop.service.impl;

import com.btpj.shop.dao.RoleMapper;
import com.btpj.shop.dao.UserMapper;
import com.btpj.shop.dao.UserRoleMapper;
import com.btpj.shop.dto.param.UserParam;
import com.btpj.shop.entity.User;
import com.btpj.shop.entity.UserRole;
import com.btpj.shop.service.UserService;
import com.btpj.shop.utils.JwtTokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

@Service
public class UserServiceImpl implements UserService, UserDetailsService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    PasswordEncoder passwordEncoder;

    @Resource
    JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    @Override
    public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
        User user = userMapper.selectByName(name);
        if (user == null) {
            user = new User();
        }
        user.setRoles(roleMapper.selectByUserId(user.getId()));
        return user;
    }

    @Override
    public User getUserByName(String name) {
        return userMapper.selectByName(name);
    }

    @Override
    public String login(String name, String password) {
        String jwtToken = null;

        // 客户端传递账号和加密后的密码
        try {
            User user = (User) loadUserByUsername(name);
            // 密码不匹配
            if (!passwordEncoder.matches(password, user.getPassword())) {
                throw new BadCredentialsException("密码错误");
            }

            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            jwtToken = tokenHead + " " + jwtTokenUtil.generateToken(name);
        } catch (Exception e) {
            LOGGER.error("用户 :{} , 登录失败 :{}", name, e.getMessage());
        }
        return jwtToken;
    }

    @Override
    public User getUserInfo() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            return null;
        }

        return (User) authentication.getPrincipal();
    }

    @Override
    public boolean checkPassword(String password) {
        User user = getUserInfo();
        return passwordEncoder.matches(password, user.getPassword());
    }

    @Override
    @Transactional
    public boolean changePwd(String newPassword) {
        User user = getUserInfo();
        user.setPassword(passwordEncoder.encode(newPassword));
        return userMapper.updateByPrimaryKeySelective(user) > 0;
    }

    @Override
    @Transactional
    public boolean register(String name, String password) {
        User user = new User();
        user.setName(name);
        user.setPassword(passwordEncoder.encode(password));
        user.setNickName(name);
        int userInsert = userMapper.insertSelective(user);
        UserRole userRole = new UserRole();
        userRole.setUserId(getUserByName(name).getId());
        userRole.setRoleId(2L);
        int userRoleInsert = userRoleMapper.insertSelective(userRole);
        return userInsert > 0 && userRoleInsert > 0;
    }

    @Override
    public boolean exists(Long id) {
        return userMapper.selectByPrimaryKey(id) != null;
    }

    @Transactional
    @Override
    public boolean lockOrUnlockUsers(Long[] ids, Boolean locked) {
        return userMapper.updateLockedByIds(ids, locked) > 0;
    }

    @Transactional
    @Override
    public boolean updateUser(UserParam param) {
        User user = getUserInfo();
        BeanUtils.copyProperties(param, user);
        return userMapper.updateByPrimaryKeySelective(user) > 0;
    }
}
